/*     */ package com.zimbra.cs.mailclient.smtp;
/*     */ 
/*     */ import com.google.common.base.CharMatcher;
/*     */ import com.google.common.base.Preconditions;
/*     */ import com.google.common.base.Splitter;
/*     */ import com.google.common.base.Strings;
/*     */ import com.google.common.collect.Iterables;
/*     */ import com.sun.mail.smtp.SMTPMessage;
/*     */ import com.zimbra.common.util.Log;
/*     */ import com.zimbra.cs.mailclient.CommandFailedException;
/*     */ import com.zimbra.cs.mailclient.MailConfig;
/*     */ import com.zimbra.cs.mailclient.MailConfig.Security;
/*     */ import com.zimbra.cs.mailclient.MailConnection;
/*     */ import com.zimbra.cs.mailclient.MailConnection.State;
/*     */ import com.zimbra.cs.mailclient.MailException;
/*     */ import com.zimbra.cs.mailclient.MailInputStream;
/*     */ import com.zimbra.cs.mailclient.MailOutputStream;
/*     */ import com.zimbra.cs.mailclient.auth.Authenticator;
/*     */ import com.zimbra.cs.mailclient.util.Ascii;
/*     */ import java.io.FilterOutputStream;
/*     */ import java.io.IOException;
/*     */ import java.io.InputStream;
/*     */ import java.io.OutputStream;
/*     */ import java.util.ArrayList;
/*     */ import java.util.Collections;
/*     */ import java.util.HashSet;
/*     */ import java.util.List;
/*     */ import java.util.Set;
/*     */ import java.util.TreeSet;
/*     */ import java.util.regex.Matcher;
/*     */ import java.util.regex.Pattern;
/*     */ import javax.mail.Address;
/*     */ import javax.mail.MessagingException;
/*     */ import javax.mail.internet.InternetAddress;
/*     */ import javax.mail.internet.MimeMessage;
/*     */ import javax.security.sasl.SaslException;
/*     */ import org.apache.commons.codec.binary.Base64;
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ public final class SmtpConnection
/*     */   extends MailConnection
/*     */ {
/*     */   static final String EHLO = "EHLO";
/*     */   static final String HELO = "HELO";
/*     */   static final String MAIL = "MAIL";
/*     */   static final String RCPT = "RCPT";
/*     */   static final String DATA = "DATA";
/*     */   static final String QUIT = "QUIT";
/*     */   static final String AUTH = "AUTH";
/*     */   static final String STARTTLS = "STARTTLS";
/*     */   static final String RSET = "RSET";
/*     */   private static final String LOGIN = "LOGIN";
/*  69 */   private static final String[] IGNORE_HEADERS = { "Bcc", "Resent-Bcc", "Content-Length" };
/*     */   
/*  71 */   private Set<String> invalidRecipients = new TreeSet(String.CASE_INSENSITIVE_ORDER);
/*  72 */   private Set<String> validRecipients = new TreeSet(String.CASE_INSENSITIVE_ORDER);
/*  73 */   private Set<String> serverAuthMechanisms = new HashSet();
/*  74 */   private Set<String> serverExtensions = new HashSet();
/*     */   
/*     */   public SmtpConnection(SmtpConfig config) {
/*  77 */     super(config);
/*  78 */     Preconditions.checkNotNull(config.getHost());
/*  79 */     Preconditions.checkArgument(config.getPort() >= 0);
/*     */   }
/*     */   
/*     */   public Set<String> getValidRecipients() {
/*  83 */     return Collections.unmodifiableSet(this.validRecipients);
/*     */   }
/*     */   
/*     */   public Set<String> getInvalidRecipients() {
/*  87 */     return Collections.unmodifiableSet(this.invalidRecipients);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private static final class SmtpDataOutputStream
/*     */     extends FilterOutputStream
/*     */   {
/* 102 */     private int last = -1;
/*     */     
/*     */     private SmtpDataOutputStream(OutputStream out) {
/* 105 */       super();
/*     */     }
/*     */     
/*     */     public void write(int b) throws IOException
/*     */     {
/* 110 */       switch (b) {
/*     */       case 13: 
/* 112 */         crlf();
/* 113 */         break;
/*     */       case 10: 
/* 115 */         if (this.last != 13) {
/* 116 */           crlf();
/*     */         }
/*     */         break;
/*     */       case 46: 
/* 120 */         switch (this.last) {
/*     */         case -1: 
/*     */         case 10: 
/*     */         case 13: 
/* 124 */           dot();
/*     */         }
/*     */         
/* 127 */         dot();
/* 128 */         break;
/*     */       default: 
/* 130 */         super.write(b);
/*     */       }
/*     */       
/* 133 */       this.last = b;
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */     public void end()
/*     */       throws IOException
/*     */     {
/* 155 */       switch (this.last) {
/*     */       case -1: 
/*     */       case 10: 
/*     */       case 13: 
/*     */         break;
/*     */       default: 
/* 161 */         crlf();
/*     */       }
/*     */       
/* 164 */       dot();
/* 165 */       crlf();
/*     */     }
/*     */     
/*     */     private void dot() throws IOException {
/* 169 */       super.write(46);
/*     */     }
/*     */     
/*     */     private void crlf() throws IOException {
/* 173 */       super.write(13);
/* 174 */       super.write(10);
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */     public void flush() {}
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */   protected MailInputStream newMailInputStream(InputStream is)
/*     */   {
/* 187 */     if (getLogger().isTraceEnabled()) {
/* 188 */       return new MailInputStream(is, getLogger());
/*     */     }
/* 190 */     return new MailInputStream(is);
/*     */   }
/*     */   
/*     */ 
/*     */   protected MailOutputStream newMailOutputStream(OutputStream os)
/*     */   {
/* 196 */     if (getLogger().isTraceEnabled()) {
/* 197 */       return new MailOutputStream(os, getLogger());
/*     */     }
/* 199 */     return new MailOutputStream(os);
/*     */   }
/*     */   
/*     */   protected void processGreeting()
/*     */     throws IOException
/*     */   {
/*     */     for (;;)
/*     */     {
/* 207 */       Reply reply = Reply.parse(this.mailIn.readLine());
/* 208 */       this.mailIn.trace();
/* 209 */       if (reply == null) {
/* 210 */         throw new MailException("Did not receive greeting from server");
/*     */       }
/* 212 */       if (reply.code != 220) {
/* 213 */         throw new IOException("Expected greeting, but got: " + reply);
/*     */       }
/* 215 */       if (reply.last) {
/*     */         break;
/*     */       }
/*     */     }
/*     */     
/*     */ 
/* 221 */     if (ehlo() != 250) {
/* 222 */       helo();
/*     */     }
/*     */     
/*     */ 
/* 226 */     if ((this.config.getSecurity() != MailConfig.Security.TLS_IF_AVAILABLE) || (!this.serverExtensions.contains("STARTTLS")))
/*     */     {
/* 228 */       checkAuthExtensions();
/*     */     }
/*     */     
/* 231 */     setState(MailConnection.State.NOT_AUTHENTICATED);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private int ehlo()
/*     */     throws IOException
/*     */   {
/* 241 */     Reply reply = sendCommand("EHLO", getSmtpConfig().getDomain());
/* 242 */     return readHelloReplies("EHLO", reply);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private void helo()
/*     */     throws IOException
/*     */   {
/* 251 */     Reply reply = sendCommand("HELO", getSmtpConfig().getDomain());
/* 252 */     int replyCode = readHelloReplies("HELO", reply);
/* 253 */     if (replyCode != 250) {
/* 254 */       throw new CommandFailedException("HELO", reply.toString());
/*     */     }
/*     */   }
/*     */   
/* 258 */   private static final Pattern PAT_EXTENSION = Pattern.compile("([^\\s]+)(.*)");
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   private int readHelloReplies(String command, Reply firstReply)
/*     */     throws IOException
/*     */   {
/* 270 */     Reply reply = firstReply;
/* 271 */     int line = 1;
/* 272 */     this.serverExtensions.clear();
/* 273 */     this.serverAuthMechanisms.clear();
/*     */     for (;;)
/*     */     {
/* 276 */       if (reply.text == null) {
/* 277 */         throw new CommandFailedException(command, "Invalid server response at line " + line + ": " + reply);
/*     */       }
/* 279 */       if (reply.code != 250) {
/* 280 */         return reply.code;
/*     */       }
/*     */       
/* 283 */       if (line > 1)
/*     */       {
/* 285 */         Matcher matcher = PAT_EXTENSION.matcher(reply.text);
/* 286 */         if (matcher.matches()) {
/* 287 */           String extName = matcher.group(1).toUpperCase();
/* 288 */           this.serverExtensions.add(extName);
/* 289 */           if (extName.equals("AUTH"))
/*     */           {
/* 291 */             Splitter splitter = Splitter.on(CharMatcher.WHITESPACE).trimResults().omitEmptyStrings();
/* 292 */             for (String mechanism : splitter.split(matcher.group(2))) {
/* 293 */               this.serverAuthMechanisms.add(mechanism.toUpperCase());
/*     */             }
/*     */           }
/*     */         }
/*     */       }
/* 298 */       if (reply.last) {
/* 299 */         this.mailIn.trace();
/* 300 */         return 250;
/*     */       }
/* 302 */       reply = Reply.parse(this.mailIn.readLine());
/*     */       
/* 304 */       line++;
/*     */     }
/*     */   }
/*     */   
/*     */   private void checkAuthExtensions() throws MailException {
/* 309 */     if (this.config.getAuthenticationId() == null) {
/* 310 */       return;
/*     */     }
/* 312 */     if (!this.serverExtensions.contains("AUTH")) {
/* 313 */       throw new MailException("The server doesn't support SMTP-AUTH.");
/*     */     }
/* 315 */     String mech = this.config.getMechanism();
/* 316 */     if (mech != null) {
/* 317 */       if (!this.serverAuthMechanisms.contains(mech.toUpperCase())) {
/* 318 */         throw new MailException("Auth mechanism mismatch client=" + mech + ",server=" + this.serverAuthMechanisms);
/*     */       }
/*     */     }
/* 321 */     else if (this.serverAuthMechanisms.contains("LOGIN")) {
/* 322 */       this.config.setMechanism("LOGIN");
/* 323 */     } else if (this.serverAuthMechanisms.contains("PLAIN")) {
/* 324 */       this.config.setMechanism("PLAIN");
/* 325 */     } else if (this.serverAuthMechanisms.contains("CRAM-MD5")) {
/* 326 */       this.config.setMechanism("CRAM-MD5");
/* 327 */     } else if (this.serverAuthMechanisms.contains("DIGEST-MD5")) {
/* 328 */       this.config.setMechanism("DIGEST-MD5");
/*     */     } else {
/* 330 */       throw new MailException("No auth mechanism supported: " + this.serverAuthMechanisms);
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */   protected void sendLogin(String user, String pass)
/*     */     throws IOException
/*     */   {
/* 338 */     Reply reply = sendCommand("AUTH", "LOGIN");
/* 339 */     if (reply.code != 334) {
/* 340 */       throw new CommandFailedException("AUTH", reply.toString());
/*     */     }
/*     */     
/*     */ 
/* 344 */     reply = sendCommand(Base64.encodeBase64(user.getBytes()), null);
/* 345 */     if (reply.code != 334) {
/* 346 */       if (reply.isPositive()) {
/* 347 */         return;
/*     */       }
/* 349 */       throw new CommandFailedException("AUTH", "AUTH LOGIN failed: " + reply);
/*     */     }
/*     */     
/*     */ 
/*     */ 
/* 354 */     reply = sendCommand(Base64.encodeBase64(pass.getBytes()), null);
/* 355 */     if (!reply.isPositive()) {
/* 356 */       throw new CommandFailedException("AUTH", "AUTH LOGIN failed: " + reply);
/*     */     }
/*     */   }
/*     */   
/*     */   protected void sendAuthenticate(boolean ir) throws IOException {
/*     */     Reply reply;
/*     */     Reply reply;
/* 363 */     if (this.authenticator.hasInitialResponse()) {
/* 364 */       reply = sendCommand("AUTH", this.authenticator.getMechanism() + ' ' + Ascii.toString(Base64.encodeBase64(this.authenticator.getInitialResponse())));
/*     */     }
/*     */     else {
/* 367 */       reply = sendCommand("AUTH", this.authenticator.getMechanism());
/*     */     }
/*     */     for (;;)
/*     */     {
/* 371 */       switch (reply.code) {
/*     */       case 235: 
/* 373 */         if (this.authenticator.isComplete()) {
/* 374 */           return;
/*     */         }
/* 376 */         throw new SaslException("SASL client auth not complete yet S: " + reply.toString());
/*     */       
/*     */       case 334: 
/* 379 */         byte[] challenge = Strings.isNullOrEmpty(reply.text) ? new byte[0] : Base64.decodeBase64(reply.text);
/* 380 */         byte[] response = this.authenticator.evaluateChallenge(challenge);
/* 381 */         if (response != null) {
/* 382 */           reply = sendCommand(Ascii.toString(Base64.encodeBase64(response)), null);
/*     */         } else
/* 384 */           reply = sendCommand("", null);
/*     */         break;
/*     */       }
/*     */     }
/* 388 */     throw new CommandFailedException("AUTH", reply.toString());
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void logout() {}
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   protected void startTls()
/*     */     throws IOException
/*     */   {
/* 403 */     super.startTls();
/* 404 */     if (ehlo() != 250) {
/* 405 */       helo();
/*     */     }
/* 407 */     checkAuthExtensions();
/*     */   }
/*     */   
/*     */   protected void sendStartTls() throws IOException
/*     */   {
/* 412 */     sendCommand("STARTTLS", null);
/*     */   }
/*     */   
/*     */   private String getSender(MimeMessage msg) throws MessagingException {
/* 416 */     String sender = null;
/* 417 */     if ((msg instanceof SMTPMessage)) {
/* 418 */       sender = ((SMTPMessage)msg).getEnvelopeFrom();
/* 419 */       if ((sender != null) && (sender.length() >= 2) && (sender.startsWith("<")) && (sender.endsWith(">")))
/*     */       {
/*     */ 
/* 422 */         sender = sender.substring(1, sender.length() - 1);
/*     */       }
/*     */     }
/* 425 */     if (sender == null) {
/* 426 */       Address[] fromAddrs = msg.getFrom();
/* 427 */       if ((fromAddrs != null) && (fromAddrs.length > 0)) {
/* 428 */         sender = getAddress(fromAddrs[0]);
/*     */       }
/*     */     }
/* 431 */     return sender;
/*     */   }
/*     */   
/*     */   private String[] toString(Address[] addrs) {
/* 435 */     List<String> result = new ArrayList();
/* 436 */     for (Address addr : addrs) {
/* 437 */       String str = getAddress(addr);
/* 438 */       if (!Strings.isNullOrEmpty(str)) {
/* 439 */         result.add(str);
/*     */       }
/*     */     }
/* 442 */     return (String[])Iterables.toArray(result, String.class);
/*     */   }
/*     */   
/*     */   private String getAddress(Address address) {
/* 446 */     if ((address instanceof InternetAddress)) {
/* 447 */       return ((InternetAddress)address).getAddress();
/*     */     }
/* 449 */     return null;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void sendMessage(MimeMessage msg)
/*     */     throws IOException, MessagingException
/*     */   {
/* 461 */     sendMessage(getSender(msg), toString(msg.getAllRecipients()), msg);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void sendMessage(Address[] rcpts, MimeMessage msg)
/*     */     throws IOException, MessagingException
/*     */   {
/* 472 */     sendMessage(getSender(msg), toString(rcpts), msg);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   void sendMessage(String sender, Address[] rcpts, MimeMessage msg)
/*     */     throws IOException, MessagingException
/*     */   {
/* 481 */     sendMessage(sender, toString(rcpts), msg);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void sendMessage(String sender, String[] rcpts, MimeMessage msg)
/*     */     throws IOException, MessagingException
/*     */   {
/* 496 */     connect();
/*     */     try {
/* 498 */       sendInternal(sender, rcpts, msg, null);
/*     */     } finally {
/* 500 */       quit();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   public void sendMessage(String sender, String[] rcpts, String msg)
/*     */     throws IOException, MessagingException
/*     */   {
/* 516 */     connect();
/*     */     try {
/* 518 */       sendInternal(sender, rcpts, null, msg);
/*     */     } finally {
/* 520 */       quit();
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private String getDSNNotify(SMTPMessage message)
/*     */   {
/* 529 */     if (message.getNotifyOptions() == 0)
/* 530 */       return null;
/* 531 */     if (message.getNotifyOptions() == -1)
/* 532 */       return "NEVER";
/* 533 */     StringBuffer sb = new StringBuffer();
/* 534 */     if ((message.getNotifyOptions() & 0x1) != 0)
/* 535 */       sb.append("SUCCESS");
/* 536 */     if ((message.getNotifyOptions() & 0x2) != 0) {
/* 537 */       if (sb.length() != 0)
/* 538 */         sb.append(',');
/* 539 */       sb.append("FAILURE");
/*     */     }
/* 541 */     if ((message.getNotifyOptions() & 0x4) != 0) {
/* 542 */       if (sb.length() != 0)
/* 543 */         sb.append(',');
/* 544 */       sb.append("DELAY");
/*     */     }
/* 546 */     return sb.toString();
/*     */   }
/*     */   
/*     */   private void sendInternal(String sender, String[] recipients, MimeMessage javaMailMessage, String messageString)
/*     */     throws IOException, MessagingException
/*     */   {
/* 552 */     this.invalidRecipients.clear();
/* 553 */     this.validRecipients.clear();
/* 554 */     Collections.addAll(this.validRecipients, recipients);
/*     */     
/* 556 */     mail(sender);
/*     */     
/* 558 */     String notify = null;
/* 559 */     if (this.serverExtensions.contains("DSN")) {
/* 560 */       if ((javaMailMessage instanceof SMTPMessage))
/* 561 */         notify = getDSNNotify((SMTPMessage)javaMailMessage);
/* 562 */       if (notify == null) {
/* 563 */         notify = getSmtpConfig().getDsn();
/*     */       }
/*     */     }
/* 566 */     rcpt(recipients, notify);
/* 567 */     Reply reply = sendCommand("DATA", null);
/* 568 */     if (reply.code != 354) {
/* 569 */       throw new CommandFailedException("DATA", reply.toString());
/*     */     }
/*     */     
/* 572 */     SmtpDataOutputStream smtpData = new SmtpDataOutputStream(this.mailOut, null);
/*     */     try {
/* 574 */       if (javaMailMessage != null) {
/* 575 */         javaMailMessage.writeTo(smtpData, IGNORE_HEADERS);
/*     */       } else {
/* 577 */         smtpData.write(messageString.getBytes());
/*     */       }
/*     */     } catch (MessagingException e) {
/* 580 */       close();
/* 581 */       throw e;
/*     */     } catch (IOException e) {
/* 583 */       close();
/* 584 */       throw e;
/*     */     }
/* 586 */     smtpData.end();
/* 587 */     this.mailOut.flush();
/* 588 */     this.mailOut.trace();
/* 589 */     reply = Reply.parse(this.mailIn.readLine());
/* 590 */     this.mailIn.trace();
/* 591 */     if (reply == null) {
/* 592 */       throw new CommandFailedException("DATA", "No response");
/*     */     }
/* 594 */     if (!reply.isPositive()) {
/* 595 */       throw new CommandFailedException("DATA", reply.toString());
/*     */     }
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private Reply sendCommand(String command, String args)
/*     */     throws IOException
/*     */   {
/* 605 */     return sendCommand(command.getBytes(), args);
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */   private Reply sendCommand(byte[] command, String args)
/*     */     throws IOException
/*     */   {
/* 614 */     this.mailOut.write(command);
/* 615 */     if (!Strings.isNullOrEmpty(args)) {
/* 616 */       this.mailOut.write(32);
/* 617 */       this.mailOut.write(args);
/*     */     }
/* 619 */     this.mailOut.newLine();
/* 620 */     this.mailOut.flush();
/* 621 */     this.mailOut.trace();
/* 622 */     Reply reply = Reply.parse(this.mailIn.readLine());
/* 623 */     this.mailIn.trace();
/* 624 */     if (reply == null) {
/* 625 */       throw new CommandFailedException(new String(command), "No response from server");
/*     */     }
/* 627 */     return reply;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void mail(String from)
/*     */     throws IOException
/*     */   {
/* 638 */     if (from == null) {
/* 639 */       from = "";
/*     */     }
/* 641 */     Reply reply = sendCommand("MAIL", "FROM:" + normalizeAddress(from));
/* 642 */     if (!reply.isPositive()) {
/* 643 */       this.validRecipients.clear();
/* 644 */       throw new CommandFailedException("MAIL", reply.toString());
/*     */     }
/*     */   }
/*     */   
/*     */   private String normalizeAddress(String addr) {
/* 649 */     if ((!addr.startsWith("<")) && (!addr.endsWith(">"))) {
/* 650 */       return "<" + addr + ">";
/*     */     }
/* 652 */     return addr;
/*     */   }
/*     */   
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */ 
/*     */   void rset()
/*     */     throws IOException
/*     */   {
/* 663 */     Reply reply = sendCommand("RSET", null);
/* 664 */     if (!reply.isPositive()) {
/* 665 */       throw new CommandFailedException("RSET", reply.toString());
/*     */     }
/*     */   }
/*     */   
/*     */   private void rcpt(String[] recipients, String dsn) throws IOException {
/* 670 */     for (String recipient : recipients) {
/* 671 */       if (recipient == null) {
/* 672 */         recipient = "";
/*     */       }
/* 674 */       String cmd = "TO:" + normalizeAddress(recipient);
/* 675 */       if (dsn != null)
/* 676 */         cmd = cmd + " NOTIFY=" + dsn;
/* 677 */       Reply reply = sendCommand("RCPT", cmd);
/* 678 */       if (!reply.isPositive()) {
/* 679 */         this.validRecipients.remove(recipient);
/* 680 */         this.invalidRecipients.add(recipient);
/* 681 */         if (!getSmtpConfig().isPartialSendAllowed()) {
/* 682 */           throw new InvalidRecipientException(recipient, reply.toString());
/*     */         }
/*     */       }
/*     */     }
/* 686 */     if (this.validRecipients.isEmpty()) {
/* 687 */       throw new CommandFailedException("RCPT", "No valid recipients");
/*     */     }
/*     */   }
/*     */   
/*     */   private void quit() throws IOException {
/* 692 */     if (isClosed()) {
/* 693 */       return;
/*     */     }
/*     */     try {
/* 696 */       sendCommand("QUIT", null);
/*     */     } catch (CommandFailedException e) {
/* 698 */       getLogger().warn(e.getMessage());
/*     */     } finally {
/* 700 */       close();
/*     */     }
/*     */   }
/*     */   
/*     */   private SmtpConfig getSmtpConfig() {
/* 705 */     return (SmtpConfig)this.config;
/*     */   }
/*     */   
/*     */   private static final class Reply {
/*     */     final int code;
/*     */     String text;
/*     */     boolean last;
/*     */     
/*     */     private Reply(String line) throws IOException {
/* 714 */       if ((line == null) || (line.length() < 3)) {
/* 715 */         throw new IOException("Invalid server response: '" + line + "'");
/*     */       }
/*     */       try {
/* 718 */         this.code = Integer.parseInt(line.substring(0, 3));
/*     */       } catch (NumberFormatException e) {
/* 720 */         throw new IOException("Invalid server response: '" + line + "'");
/*     */       }
/* 722 */       if (line.length() > 4) {
/* 723 */         switch (line.charAt(3)) {
/*     */         case '-': 
/* 725 */           this.last = false;
/* 726 */           break;
/*     */         case ' ': 
/* 728 */           this.last = true;
/* 729 */           break;
/*     */         default: 
/* 731 */           throw new IOException("Invalid server response: '" + line + "'");
/*     */         }
/* 733 */         this.text = line.substring(4).trim();
/*     */       }
/*     */     }
/*     */     
/*     */     static Reply parse(String line) throws IOException {
/* 738 */       if (Strings.isNullOrEmpty(line)) {
/* 739 */         return null;
/*     */       }
/* 741 */       return new Reply(line);
/*     */     }
/*     */     
/*     */ 
/*     */ 
/*     */ 
/*     */     boolean isPositive()
/*     */     {
/* 749 */       return (200 <= this.code) && (this.code <= 299);
/*     */     }
/*     */     
/*     */     public String toString()
/*     */     {
/* 754 */       return this.code + " " + this.text;
/*     */     }
/*     */   }
/*     */ }


/* Location:              /home/mint/zimbrastore.jar!/com/zimbra/cs/mailclient/smtp/SmtpConnection.class
 * Java compiler version: 7 (51.0)
 * JD-Core Version:       0.7.1
 */